interface mac_bfm;
    logic                       phy_resetn;

    logic   [07:00]             gmii_txd;
    logic                       gmii_tx_en;
    logic                       gmii_tx_er;
    logic                       gmii_tx_clk;

    logic   [07:00]             gmii_rxd;
    logic                       gmii_rx_dv;
    logic                       gmii_rx_er;
    logic                       gmii_rx_clk;

    initial
    begin
        gmii_rx_clk = 0;
        gmii_rxd = 0;
        gmii_rx_dv = 0;
        gmii_rx_er = 0;
        forever 
        begin
            #(1s/125_000_000/2) gmii_rx_clk = ~gmii_rx_clk;
        end
    end

    clocking ether_rx_cb @ (negedge gmii_rx_clk);
        output  gmii_rx_dv;
        output  gmii_rx_er;
        output  gmii_rxd;
    endclocking

endinterface: mac_bfm
parameter               PC_MAC_ADDR     = 48'h18_31_bf_ba_11_5d;
parameter               PC_IP_ADDR      = 32'hc0_a8_01_a6;
parameter               PC_UDP_PORT     = 16'd6666;

parameter               DEV_MAC_ADDR    = 48'hc4_00_c4_01_01_02;
parameter               DEV_IP_ADDR     = 32'hc0_a8_01_66;
parameter               DEV_UDP_PORT    = 16'd4444;

/*
 * gmii接口实际测试时，在标准的以太网数据前还添加了7个8'h55和1个8'hd5，以及数据末尾的4字节CRC校验值
 * 802.3协议
 */
typedef struct packed
{
    bit     [63:00]             preamble;
    bit     [47:00]             dst_mac_addr;   // mac addr
    bit     [47:00]             src_mac_addr;   // mac addr
    bit     [15:00]             ether_type;
}head_s;

typedef struct packed
{
    bit     [03:00]             version;
    bit     [03:00]             ihl; //首部长度
    bit     [07:00]             tos;
    bit     [15:00]             tol_length;  // IP数据段的全部数据长度
    bit     [15:00]             id;
    bit     [02:00]             flags;
    bit     [12:00]             frag_offset;
    bit     [07:00]             ttl;
    bit     [07:00]             protocal;
    bit     [15:00]             checksum;
    bit     [31:00]             src_ip_addr;
    bit     [31:00]             dst_ip_addr;
}ip_s;

typedef struct packed
{
    bit     [15:00]             src_port;
    bit     [15:00]             dst_port;
    bit     [15:00]             length;
    bit     [15:00]             checksum;
    bit     [0:283] [7:0]       data; // 合并数组的声明方式  284个8bit, [msb:lsb]和[lsb:msb]声明方式对赋值是有影响的
}udp_s;

typedef struct packed
{
    bit     [15:00]             hardware_type;
    bit     [15:00]             protocal_type;
    bit     [07:00]             handware_addr_len;
    bit     [07:00]             protocal_addr_len;
    bit     [15:00]             op_code;
    bit     [47:00]             src_mac_addr;   // mac addr
    bit     [31:00]             src_ip_addr;
    bit     [47:00]             dst_mac_addr;   // mac addr
    bit     [31:00]             dst_ip_addr;
    bit     [143:00]            pad;    // 18个字节
}arp_s;

typedef struct packed
{
    head_s  head;
    arp_s arp;
    bit     [31:00]             checksum;
}arp_pck_s;

/*
 * ping命令时，全部数据40个字节
 */
typedef struct packed
{
    bit     [07:00]             type1;
    bit     [07:00]             code;
    bit     [15:00]             checksum;

    /*
     * 下面的数据，slave原样返回
     */
    // 00_01
    bit     [15:00]             id;   //  identifier(BE, LE)
    // 01_3b, 递增
    bit     [15:00]             seq_num;   // sequnce number(BE, LE)

    // 61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:61:62:63:64:65:66:67:68:69
    bit     [0:31] [0:7]        data; // 32个8bit元素组成的数组 
}imcp_s;

typedef struct packed
{
    head_s  head;
    ip_s    ip;
    udp_s   udp;
    bit     [31:00]             checksum;
}udp_pck_s;

typedef struct packed
{
    head_s  head;
    ip_s ip;
    imcp_s icmp;
    bit     [31:00]             checksum;
}ping_pck_s;

typedef enum
{
    IPV4 = 32'h0800,
    ARP  = 32'h0806
}FRAME_TYPE;

typedef enum
{
    ARP_REQ = 1,
    ARP_RES = 2
}ARP_OP_TYPE;


